package Structure.MyLinkedList;

import java.util.function.Consumer;

/**
 * @author wang'ji'cheng
 * @date 2025/7/25
 */
public class SingleLinkedList {

    //头节点 (指针)p
    private Node head;
    //大小
    private int size;

    public int getSize(){
        return this.size;
    }

    /**
     * 节点类
     */
    class Node {
        //值
        Object value;
        //下一个指针
        Node next;

        public Node(Object value, Node next) {
            this.value = value;
            this.next = next;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "value=" + value +
                    ", next=" + next +
                    '}';
        }
    }


    //头插法
    public void addFirst(Object value) {

        /**
         * 链表为空时，head是null，创建一个新节点，新节点的下一个指针为空，把新节点的引用赋值给head ，这个节点就变成头结点
         * 链表非空时，创建一个节点，新节点的下一个指针，指向原来的头结点，也就是head的引用，然后再把这个节点的引用，赋值给head，让当前节点成为头结点
         */
        head = new Node(value, head);
        size++;

    }

    //遍历
    public void loop() {
        //先获取头结点，判断当前连表是否为空，p可以视为一个指针，一开始指向头结点，也可以成为当前节点对象的引用
        Node p = head;
        while (p != null) {
            System.out.println(p.value);
            //获取当前节点的下一个节点的位置。然后让p指向他  p.next表示当前节点的下一个节点对象，再把这个引用复制给原来的p，这样
            p = p.next;
        }
    }

    //for循环遍历
    public void forLoop() {
        for (Node p = head; p != null; p = p.next) {
            System.out.println(p);
        }
    }


    //尾插法
    public void addLast(Object value) {
        //判断链表是否为空，如果为空，尾插法头插法没有区别
        if (head == null) {
            head = new Node(value, null);
            size++;
        } else {
            //链表不为空，则需要先找到为节点
            Node p = head;
            while (p.next != null) {
                p = p.next;
            }
            //当前指针的下一个位置为null,找到尾节点了
            p.next = new Node(value, null);
            size++;
        }

    }

    //遍历的通用写法
    public void loop2(Consumer<Integer> consumer) {
        Node p = head;
        while (p != null) {
            consumer.accept((Integer) p.value);
            p = p.next;
        }
    }

    //根据索引获取链表的值
    public Object get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
        Node p = head;
        for (int i = 0; i <= index; i++) {
            p = p.next;
        }
        return p.value;
    }

    //获取节点
    public Node getNode(int index) {
        int i = 0;
        for (Node p = head; p != null; p = p.next) {
            if (i == index) {
                return p;
            }
            i++;
        }
        return null;
    }

    //插入节点
    public void insert(int index, Object value) {
        if (index < 0 || index >= size) {
            System.out.println("索引越界");
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        } else if (index == 0) {
            Node currNode = new Node(value, head);
            head = currNode;
        } else {
            //获取当前索引的节点
            Node pre = getNode(index - 1);
            Node curNode = new Node(value, pre.next);
            pre.next = curNode;
        }
        size++;

    }

    //删除节点
    public void remove(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        } else if (index == 0) {
            head = head.next;
        } else {
            Node pre = getNode(index - 1);
            pre.next = pre.next.next;
            size--;
        }

    }


}
